# Copyright 2007 Eloff Enterprises
#
# Licensed under the BSD License (the "License").
# You may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://rwig.googlecode.com/files/LICENSE
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.  See the License for the specific language governing
# permissions and limitations under the License.
#
# Originally developed by Daniel Eloff.

from __future__ import with_statement

import os
import re
import conversion

re_method = re.compile(r'(?P<ret>[a-zA-Z0-9_]+?)\s+?(?P<func>[a-zA-Z0-9_]+?)\s*?\((?P<args>[^)]*?)\)(?:\s*?->\s*?(?P<alias>[a-zA-Z0-9_]+))?(?:\s+?/\*(?P<doc>.+?)\*/)?', re.DOTALL)

class Module(object):
    def __init__(self, name, alias, fromlist):
        self.name = name
        self.alias = alias if alias else name
        self.factory = None
        self.fromlist = fromlist
        self.methods = []
        
    def add_method(self, method):
        self.methods.append(method)
        
class Method(object):
    def __init__(self, name, alias, ret_type, arg_types, doc=None):
        self.name = name
        self.alias = alias if alias else name
        self.ret_type = conversion.get_type(ret_type.lower())
        self.arg_types = [conversion.get_type(a) for a in arg_types]
        self.doc = ('Automatically generated wrapper for %s by RWIG.' % name) if doc is None else doc

class RWIGInterface(object):
    def __init__(self, path):
        self.path = path if os.path.isabs(path) else os.path.join(os.path.abspath(os.path.curdir), path)
        self.modules = []
        
        with file(self.path, 'rb') as f:
            self.parse_lines(iter(f))
            
    def parse_lines(self, lines):
        lines = iter(lines)
        
        for line in lines:
            if ':' in line:
                section, import_ = (s.strip() for s in line.split(':'))
                if section.lower() == 'module':
                    name, from_ = (s.strip() for s in import_.split('import'))
                    if name.startswith('from'):
                        name = name[4:].strip()
                        
                    if '->' in name:
                        name, alias = (s.strip() for s in name.split('->'))
                    else:
                        alias = name.replace('.', '_')
                        
                    fromlist = [s.strip() for s in from_.split(',')]
                        
                    self.modules.append(self.parse_module(Module(name, alias, fromlist), lines))
                
    def parse_module(self, module, lines):        
        for line in lines:
            section, data = (s.strip() for s in line.split(':'))
            if section.lower() == 'factory':
                module.factory = data
            elif section.lower() == 'methods':
                self.parse_methods(module, lines)
                break
                
        return module
                
    def parse_methods(self, module, lines):
        def is_method(line):
            return line.strip()
              
        methods = []
        for line in lines:
            if is_method(line):
                methods.append(line)
            else:
                break
            
        methods = '\n'.join(methods)
        
        for m in re_method.finditer(methods):
            ret, func, args, alias, doc = m.group('ret', 'func', 'args', 'alias', 'doc')
            
            method = Method(func, alias, ret, [a.strip() for a in args.split(',')], doc)
            module.add_method(method)
            
                